/**
 * CoffeeMilk (C) 2010 Amen Hamdan
 * 
 * See the NOTICE file distributed with this work for additional 
 * information regarding copyright ownership.  This file is licenses
 * to you under the Apache License, Version 2.0 (the "License"); you 
 * may not use this file except in compliance with the License.  You 
 * may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 *     
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 
 * implied. See the License for the specific language governing 
 * permissions and limitations under the License.    
 * 
 */
package ameen.rtm.coffeemilk.ui;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.SystemTray;
import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.border.EtchedBorder;

import ameen.rtm.coffeemilk.RtmTaskListModel;
import ameen.rtm.coffeemilk.persistency.PersistencyManager;
import ameen.rtm.coffeemilk.persistency.SettingsStore;
import ameen.rtm.coffeemilk.ui.util.TaskSortHandler;
import ameen.rtm.coffeemilk.ui.util.ToolbarFactory;
import ameen.rtm.lib.RtmException;
import ameen.rtm.lib.RtmService;
import ameen.rtm.lib.types.RtmList;
import ameen.rtm.lib.types.TasksVector;

@SuppressWarnings("serial")
public class MainUiFrame extends JFrame implements PropertyChangeListener {
	private String newTaskText;
	private TaskSortHandler fSorter = new TaskSortHandler();  //  @jve:decl-index=0:

	private Image appIconImage = Toolkit.getDefaultToolkit().getImage(getClass().getResource("coffeemilk.png"));
	private TrayIcon trayIcon = null;
	private JPanel jContentPane = null;
	private JPanel mainContentPanel = null;
	private JPanel toolbarPanel = null;
	private JToolBar jToolBar = null;
	private JTextField newTaskTextField = null;
	private JButton jSettingsButton = null;
	private JButton jGotoWebsite = null;
	private JButton jRefreshButton = null;
	private JButton jAddButton = null;
	private RtmService fRtmService;  //  @jve:decl-index=0:
	private SettingsStore fSettings;  //  @jve:decl-index=0:
	private JButton jSortCriteriaButton = null;
	
	/**
	 * This is the default constructor
	 */
	public MainUiFrame() {
		super();
		initialize();
	}

	/**
	 * This method initializes this
	 * 
	 * @return void
	 */
	private void initialize() {
		this.setSize(300, 400);
		this.setIconImage(appIconImage);
		this.setContentPane(getJContentPane());
		this.setTitle("CoffeeMilk");
	
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosed(WindowEvent we) {
				fSettings.setMainWindowHeight(getHeight());
				fSettings.setMainWindowWidth(getWidth());
				PersistencyManager.writeSettings(fSettings);
			}
		});
	}

	private void updateCloseOperationPolicy() {
		if(!fSettings.isMinimizeToTray()) {
			this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			if(trayIcon != null) {
				SystemTray.getSystemTray().remove(trayIcon);
			}
		} else {
			this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
			
			if(trayIcon == null) {
				trayIcon = new TrayIcon(appIconImage);
				trayIcon.setImageAutoSize(true);
				trayIcon.addMouseListener(new MouseAdapter() {
					@Override
					public void mouseClicked(MouseEvent e) {
						if(e.getClickCount() >= 2) {
							boolean visibleStatus = MainUiFrame.this.isVisible();
							MainUiFrame.this.setVisible(!visibleStatus);
						}
					}
				});
				PopupMenu trayIconMenu = new PopupMenu();
				MenuItem exitMenuItem = new MenuItem("  Exit  ");
				exitMenuItem.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						MainUiFrame.this.dispose();
						SystemTray.getSystemTray().remove(trayIcon);
					}
				});
				trayIconMenu.add(exitMenuItem);
				trayIcon.setPopupMenu(trayIconMenu);
			}
			try {
				SystemTray.getSystemTray().add(trayIcon);
			} catch (AWTException e) {
				System.err.println("Could not init system tray icon. Reason: " + e.toString());
				this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			}
		}
	}
	
	public void restoreSize() {
		int width = fSettings.getMainWindowWidth();
		int height = fSettings.getMainWindowHeight();
		
		if( (width == SettingsStore.UNSET) || (height == SettingsStore.UNSET) ){
			return;
		}
		setSize(width, height);
	}
	/**
	 * This method initializes jContentPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getJContentPane() {
		if (jContentPane == null) {
			BorderLayout borderLayout = new BorderLayout();
			borderLayout.setHgap(0);
			borderLayout.setVgap(0);
			jContentPane = new JPanel();
			jContentPane.setLayout(borderLayout);
			jContentPane.add(getMainContentPanel(), BorderLayout.CENTER);
			jContentPane.add(getToolbarPanel(), BorderLayout.NORTH);
		}
		return jContentPane;
	}

	/**
	 * This method initializes mainContentPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	public JPanel getMainContentPanel() {
		if (mainContentPanel == null) {
			mainContentPanel = new JPanel();
			mainContentPanel.setLayout(new BorderLayout());
		}
		return mainContentPanel;
	}

	/**
	 * This method initializes toolbarPanel	
	 * 	
	 * @return javax.swing.JPanel	
	 */
	private JPanel getToolbarPanel() {
		if (toolbarPanel == null) {
			BorderLayout borderLayout1 = new BorderLayout();
			borderLayout1.setHgap(5);
			borderLayout1.setVgap(3);
			toolbarPanel = new JPanel();
			toolbarPanel.setLayout(borderLayout1);
			toolbarPanel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
			toolbarPanel.add(getJToolBar(), BorderLayout.NORTH);
		}
		return toolbarPanel;
	}

	/**
	 * This method initializes jToolBar	
	 * 	
	 * @return javax.swing.JToolBar	
	 */
	private JToolBar getJToolBar() {
		if (jToolBar == null) {
			jToolBar = new JToolBar();
			jToolBar.setFloatable(false);
			jToolBar.setName("CoffeeMilk Toolbar");
			jToolBar.add(getNewTaskTextField());
			jToolBar.add(getJAddButton());
			jToolBar.add(new JSeparator(SwingConstants.VERTICAL));
			jToolBar.add(getJSortCriteriaButton());
			jToolBar.add(getJRefreshButton());
			jToolBar.add(getJGotoWebsite());
			jToolBar.add(new JSeparator(SwingConstants.VERTICAL));
			jToolBar.add(getJSettingsButton());
		}
		return jToolBar;
	}

	/**
	 * This method initializes newTaskTextField	
	 * 	
	 * @return javax.swing.JTextField	
	 */
	private JTextField getNewTaskTextField() {
		if (newTaskTextField == null) {
			newTaskTextField = new JTextField();
			newTaskTextField.addFocusListener(new FocusAdapter() {   
				public void focusGained(FocusEvent e) {    
					newTaskText = "";
					newTaskTextField.setText("");
					newTaskTextField.setForeground(Color.BLACK);
					jAddButton.setEnabled(true);
				}
				public void focusLost(FocusEvent e) {
					newTaskTextField.setForeground(Color.LIGHT_GRAY);
					newTaskText = newTaskTextField.getText();
					newTaskTextField.setText("add new task here");
					jAddButton.setEnabled(false);
				}
			});
			newTaskTextField.addKeyListener(new KeyAdapter() {
				@Override
				public void keyTyped(KeyEvent e) {
					if(e.getKeyChar() == KeyEvent.VK_ENTER) {
						addTaskLater(newTaskTextField.getText());
					}
					newTaskText = newTaskTextField.getText();
				}
			});
			newTaskTextField.setFont(new Font("Dialog", Font.PLAIN, 14));
		}
		return newTaskTextField;
	}

	/**
	 * This method initializes jSettingsButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJSettingsButton() {
		if (jSettingsButton == null) {
			jSettingsButton = new JButton();
			jSettingsButton.setIcon(new ImageIcon(getClass().getResource("/ameen/rtm/coffeemilk/ui/comment.png")));
			jSettingsButton.setToolTipText("settings and further information");
			
			jSettingsButton.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseClicked(MouseEvent e) {
					AboutDialog aboutDialog = new AboutDialog(MainUiFrame.this, fSettings);
					aboutDialog.setModal(true);
					aboutDialog.setVisible(true);
				}
			});
		}
		return jSettingsButton;
	}

	/**
	 * This method initializes jGotoWebsite	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJGotoWebsite() {
		if (jGotoWebsite == null) {
			jGotoWebsite = new JButton();
			jGotoWebsite.setIcon(new ImageIcon(getClass().getResource("/ameen/rtm/coffeemilk/ui/world.png")));
			jGotoWebsite.setToolTipText("goto the RTM website");
			jGotoWebsite.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					try {
						Desktop.getDesktop().browse(new URI("https://www.rememberthemilk.com"));
					} catch (Exception ex) {
					}
				}
			});
		}
		return jGotoWebsite;
	}

	/**
	 * This method initializes jRefreshButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJRefreshButton() {
		if (jRefreshButton == null) {
			jRefreshButton = new JButton();
			jRefreshButton.setIcon(new ImageIcon(getClass().getResource("/ameen/rtm/coffeemilk/ui/refresh.png")));
			jRefreshButton.setToolTipText("reload tasks / reset view");
			jRefreshButton.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					showLoadingDialog();
					SwingUtilities.invokeLater(new Runnable() {
						
						@Override
						public void run() {
							loadMainWindow();
						}
					});
				}
			});
		}
		return jRefreshButton;
	}

	/**
	 * This method initializes jAddButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJAddButton() {
		if (jAddButton == null) {
			jAddButton = new JButton();
			jAddButton.setIcon(new ImageIcon(getClass().getResource("/ameen/rtm/coffeemilk/ui/plus.png")));
			jAddButton.setPreferredSize(new Dimension(32, 32));
			jAddButton.setToolTipText("add a new task");
			jAddButton.addMouseListener(new MouseAdapter() {
				@Override
				public void mouseClicked(MouseEvent e) {
					addTaskLater(newTaskText);
				}
			});
		}
		return jAddButton;
	}

	public void addTaskLater(final String taskText) {
		SwingUtilities.invokeLater(new Runnable() {
			
			@Override
			public void run() {
				try {
					fRtmService.createTask(newTaskText);
				} catch (RtmException rtme) {
					rtme.printStackTrace();
				}
			}
		});
	}
	public void setRtmService(RtmService rtmService) {
		fRtmService = rtmService;
	}
	
	public void setSettings(SettingsStore settings) {
		fSettings = settings;
		fSettings.addPropertyChangeListener(this);
		updateCloseOperationPolicy();
	}

	public void showLoadingDialog() {
		this.getMainContentPanel().removeAll();
		JLabel loadingLabel = new JLabel("Loading Data");
		loadingLabel.setHorizontalAlignment(SwingConstants.CENTER);
		loadingLabel.setFont(new Font("Dialog", Font.BOLD, 14));
		loadingLabel.setForeground(Color.GRAY);
		this.getMainContentPanel().add(loadingLabel,BorderLayout.CENTER);
		this.validate();
	}
	
	public final void loadMainWindow() {
		Vector<RtmList> listEntries = new Vector<RtmList>();
		try {
			listEntries = fRtmService.getLists();
		} catch (RtmException rtme) {
			rtme.printStackTrace();
		}
		
		Map<String, TasksVector> tasksMap = new HashMap<String, TasksVector>();
		try {
			fSorter.clear();
			tasksMap = fRtmService.getTaskList();
			for(RtmList currentList : listEntries) {
				TasksVector currentTasks = tasksMap.get(currentList.getId());
				if(currentTasks != null) {
					currentList.setTasks(currentTasks);
					fSorter.addTaskList(currentTasks);
					if(currentTasks.size() == 0) {
						currentList.setExpanded(false);
					}
				} else {
					TasksVector newVector = new TasksVector();
					tasksMap.put(currentList.getId(), newVector);
					currentList.setTasks(newVector);
					currentList.setExpanded(false);
				}
			}
		} catch (RtmException rtme) {
			rtme.printStackTrace();
		}

		TaskListPanel taskListPanel = new TaskListPanel();
		taskListPanel.setTaskListModel(new RtmTaskListModel(tasksMap, listEntries));
		this.getMainContentPanel().removeAll();
		this.getMainContentPanel().add(taskListPanel, BorderLayout.CENTER);
		this.validate();
	}

	/**
	 * This method initializes jSortCriteriaButton	
	 * 	
	 * @return javax.swing.JButton	
	 */
	private JButton getJSortCriteriaButton() {
		if (jSortCriteriaButton == null) {
			jSortCriteriaButton = new JButton();
			jSortCriteriaButton.setIcon(new ImageIcon(getClass().getResource("/ameen/rtm/coffeemilk/ui/sort.png")));
			jSortCriteriaButton.setToolTipText("set sort criteria");
			jSortCriteriaButton.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					JPopupMenu menu = ToolbarFactory.createSortCriteriaPopup(fSorter);
					menu.show(jSortCriteriaButton, 0, jSortCriteriaButton.getHeight());
					
				}
			});
		}
		return jSortCriteriaButton;
	}

	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		if(evt.getPropertyName().equals(SettingsStore.SYSTEMTRAY_ENABLED)) {
			updateCloseOperationPolicy();
		}
	}
}
